﻿Imports System
Imports System.Diagnostics
Imports System.Workflow.ComponentModel

Namespace System.Workflow.Runtime
    Public Class WorkflowQueue
        ' Events
        Public Custom Event QueueItemArrived As EventHandler([Of] QueueEventArgs)
            AddHandler(ByVal value As EventHandler([Of] QueueEventArgs))
                If (value Is Nothing) Then
                    Throw New ArgumentNullException("value")
                End If
                SyncLock Me.qService.SyncRoot
                    Me.qService.GetQueueState(Me.queueName).SynchronousListeners.Add(New ActivityExecutorDelegateInfo([Of] QueueEventArgs)(value, Me.qService.CallingActivity))
                End SyncLock
            End AddHandler
            RemoveHandler(ByVal value As EventHandler([Of] QueueEventArgs))
                If (value Is Nothing) Then
                    Throw New ArgumentNullException("value")
                End If
                SyncLock Me.qService.SyncRoot
                    Me.qService.GetQueueState(Me.queueName).SynchronousListeners.Remove(New ActivityExecutorDelegateInfo([Of] QueueEventArgs)(value, Me.qService.CallingActivity))
                End SyncLock
            End RemoveHandler
        End Event
        Public Custom Event QueueItemAvailable As EventHandler([Of] QueueEventArgs)
            AddHandler(ByVal value As EventHandler([Of] QueueEventArgs))
                If (value Is Nothing) Then
                    Throw New ArgumentNullException("value")
                End If
                SyncLock Me.qService.SyncRoot
                    Dim queueState As EventQueueState = Me.qService.GetQueueState(Me.queueName)
                    Dim item As New ActivityExecutorDelegateInfo([Of] QueueEventArgs)(value, Me.qService.CallingActivity)
                    queueState.AsynchronousListeners.Add(item)
                    WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, "WorkflowQueue:QueueItemAvailable subscribe for activity '{0}' with context Id {1}", New Object() { item.ActivityQualifiedName, item.ContextId })
                    If (queueState.AsynchronousListeners.Count = 1) Then
                        Me.qService.NotifyAsynchronousSubscribers(Me.queueName, queueState, queueState.Messages.Count)
                    End If
                End SyncLock
            End AddHandler
            RemoveHandler(ByVal value As EventHandler([Of] QueueEventArgs))
                SyncLock Me.qService.SyncRoot
                    Dim item As New ActivityExecutorDelegateInfo([Of] QueueEventArgs)(value, Me.qService.CallingActivity)
                    If Not Me.qService.GetQueueState(Me.queueName).AsynchronousListeners.Remove(item) Then
                        WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, "WorkflowQueue:QueueItemAvailable unsubscribe failed for activity '{0}' with context Id {1} ", New Object() { item.ActivityQualifiedName, item.ContextId })
                    End If
                End SyncLock
            End RemoveHandler
        End Event

        ' Methods
        Friend Sub New(ByVal qService As WorkflowQueuingService, ByVal queueName As IComparable)
            Me.qService = qService
            Me.queueName = queueName
        End Sub

        Public Function Dequeue() As Object
            SyncLock Me.qService.SyncRoot
                Me.qService.Peek(Me.queueName)
                Return Me.qService.DequeueEvent(Me.queueName)
            End SyncLock
        End Function

        Public Sub Enqueue(ByVal item As Object)
            SyncLock Me.qService.SyncRoot
                Me.qService.EnqueueEvent(Me.queueName, item)
            End SyncLock
        End Sub

        Public Function Peek() As Object
            SyncLock Me.qService.SyncRoot
                Return Me.qService.Peek(Me.queueName)
            End SyncLock
        End Function

        Public Sub RegisterForQueueItemArrived(ByVal eventListener As IActivityEventListener([Of] QueueEventArgs))
            If (eventListener Is Nothing) Then
                Throw New ArgumentNullException("eventListener")
            End If
            SyncLock Me.qService.SyncRoot
                Me.qService.GetQueueState(Me.queueName).SynchronousListeners.Add(New ActivityExecutorDelegateInfo([Of] QueueEventArgs)(eventListener, Me.qService.CallingActivity))
            End SyncLock
        End Sub

        Public Sub RegisterForQueueItemAvailable(ByVal eventListener As IActivityEventListener([Of] QueueEventArgs))
            Me.RegisterForQueueItemAvailable(eventListener, Nothing)
        End Sub

        Public Sub RegisterForQueueItemAvailable(ByVal eventListener As IActivityEventListener([Of] QueueEventArgs), ByVal subscriberQualifiedName As String)
            If (eventListener Is Nothing) Then
                Throw New ArgumentNullException("eventListener")
            End If
            SyncLock Me.qService.SyncRoot
                Dim queueState As EventQueueState = Me.qService.GetQueueState(Me.queueName)
                Dim item As New ActivityExecutorDelegateInfo([Of] QueueEventArgs)(eventListener, Me.qService.CallingActivity)
                If (Not subscriberQualifiedName Is Nothing) Then
                    item.SubscribedActivityQualifiedName = subscriberQualifiedName
                End If
                queueState.AsynchronousListeners.Add(item)
                WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, "WorkflowQueue:QueueItemAvailable subscribe for activity '{0}' with context Id {1}", New Object() { item.ActivityQualifiedName, item.ContextId })
                If (queueState.AsynchronousListeners.Count = 1) Then
                    Me.qService.NotifyAsynchronousSubscribers(Me.queueName, queueState, queueState.Messages.Count)
                End If
            End SyncLock
        End Sub

        Public Sub UnregisterForQueueItemArrived(ByVal eventListener As IActivityEventListener([Of] QueueEventArgs))
            If (eventListener Is Nothing) Then
                Throw New ArgumentNullException("eventListener")
            End If
            SyncLock Me.qService.SyncRoot
                Me.qService.GetQueueState(Me.queueName).SynchronousListeners.Remove(New ActivityExecutorDelegateInfo([Of] QueueEventArgs)(eventListener, Me.qService.CallingActivity))
            End SyncLock
        End Sub

        Public Sub UnregisterForQueueItemAvailable(ByVal eventListener As IActivityEventListener([Of] QueueEventArgs))
            If (eventListener Is Nothing) Then
                Throw New ArgumentNullException("eventListener")
            End If
            SyncLock Me.qService.SyncRoot
                Dim item As New ActivityExecutorDelegateInfo([Of] QueueEventArgs)(eventListener, Me.qService.CallingActivity)
                If Not Me.qService.GetQueueState(Me.queueName).AsynchronousListeners.Remove(item) Then
                    WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, "WorkflowQueue:QueueItemAvailable unsubscribe failed for activity '{0}' with context Id {1}", New Object() { item.ActivityQualifiedName, item.ContextId })
                End If
            End SyncLock
        End Sub


        ' Properties
        Public ReadOnly Property Count As Integer
            Get
                SyncLock Me.qService.SyncRoot
                    Return Me.qService.GetQueueState(Me.queueName).Messages.Count
                End SyncLock
            End Get
        End Property

        Public Property Enabled As Boolean
            Get
                SyncLock Me.qService.SyncRoot
                    Return Me.qService.GetQueueState(Me.queueName).Enabled
                End SyncLock
            End Get
            Set(ByVal value As Boolean)
                SyncLock Me.qService.SyncRoot
                    Me.qService.GetQueueState(Me.queueName).Enabled = value
                End SyncLock
            End Set
        End Property

        Public ReadOnly Property QueueName As IComparable
            Get
                Return Me.queueName
            End Get
        End Property

        Public ReadOnly Property QueuingService As WorkflowQueuingService
            Get
                Return Me.qService
            End Get
        End Property


        ' Fields
        Private qService As WorkflowQueuingService
        Private queueName As IComparable
    End Class
End Namespace

